#include "cc430f6137.h"
#include "bsp.h"
#include "mrfi.h"
#include "nwk_types.h"
#include "nwk_api.h"
#include "nwk.h"
#include "bsp_leds.h"
#include "bsp_buttons.h"
#include "RTS.h"

#define RTS_1


static  linkID_t linkID;			// link ID for device
uint8_t message[3] = {0,0,0};		// buffer for both sending and receiving messages					

uint8_t sleepTime=2;				// mem location for CTC requested sleep time

volatile uint8_t secondsSlept = 0;	// global sleep counter
volatile uint8_t gotMessage = 0;	// global flag for received message
volatile uint16_t numSeconds = 0;	// global mem for wait function sleeps
uint8_t zone = 0;


void main(void)
{
 	RTSInit();			// Init Registers for RTS Device Settings
  	CTCLink();			// Link to CTC

	while(ALWAYS)		// Loop Through Sleep Transmit Tasks
	{
	 	wait(sleepTime);							// enter low power mode
		
 	 	SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_AWAKE,0);
 	 	SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXON, 0);	// turn radio on
 	 
 	 	BSP_TOGGLE_LED1();		// DEBUG
 	 
 	 	sendTemp();									// send temperature info to CTC
 	 												// also gets new sleep time
 	 	
 	 	SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXIDLE, 0);	// turn radio off
 	 
 	 	TA1CCR0 = TA1R + SLEEP_PERIOD;				// setup vars for new sleep period
 	 	TA1CCTL0 |= CCIE;
	}
}

void RTSInit()
{
	// auto set device address
	addr_t device;
	
	#ifdef RTS_1
		device.addr[0] = 0x98;
		device.addr[1] = 0x56;
		device.addr[2] = 0x34;
		device.addr[3] = 0x12;
	#elif defined RTS_2
		device.addr[0] = 0x99;
		device.addr[1] = 0x56;
		device.addr[2] = 0x34;
		device.addr[3] = 0x12;
	#endif
	
	SMPL_Ioctl(IOCTL_OBJ_ADDR, IOCTL_ACT_SET, (void*)&device);

  	WDTCTL = WDTPW + WDTHOLD;                 		// Stop WDT for development
  	BSP_Init();										// Init Dev Board
  	SMPL_Init(RxCallBack);							// Init Wirless
  	
  	P2DIR &= ~(BIT3 + BIT2 + BIT1 + BIT0);	// P2.0, P2.1, P2.2, and P2.3 input
	P2REN |= BIT3 + BIT2 + BIT1 + BIT0;		// enable resistors on P2.0, P2.1, P2.2, and P2.3
	P2OUT |= BIT3 + BIT2 + BIT1 + BIT0;		// pullup resistors on P2.0, P2.1, P2.2, and P2.3
	zone = P2IN & 0x0F;						// read lower 4 bits of Port 2 to learn our zone
	P2REN &= ~(BIT3 + BIT2 + BIT1 + BIT0);	// turn off resistors to save power
  
  	TA1CCR0 	= SLEEP_PERIOD;						// Load cap comp register with sleep period
  	TA1CCTL0 	= CCIE;                          	// CCR0 interrupt enabled
  	TA1CTL 		= TASSEL_1 + MC_2;                	// ACLK, continuous mode
  
  	REFCTL0   |= REFMSTR + REFVSEL_1 + REFON;    	// REF module controls reference, use 2.5V reference, turn it on
  	ADC12CTL0  = ADC12SHT03 + ADC12SHT02 + ADC12ON;	// Set sample and hold time and turn on the ADC
  	ADC12CTL1  = ADC12SHP;							// Sampling timer
  	ADC12MCTL0 = ADC12INCH_10;						// Set channel 10 (temp. sensor) to memory bank 0
  	// TODO: configure sequence of channels for ADC12 to read temp then battery voltage
  	ADC12MCTL1 = ADC12INCH_11;						// memory register 1: channel 11 ((AVcc-AVss)/2)

  	ADC12CTL0 |= ADC12ENC;				// Enable conversion	
}

void CTCLink()
{
	int i;
	int connected = FALSE;
	uint8_t size;
	
	for(i=0;i<5;i++)						// make max of 5 attempts to make quick CTC connection
	{
		BSP_TOGGLE_LED2();	// DEBUG
		
		SMPL_Send(SMPL_LINKID_USER_UUD, message, sizeof(message));	// send link message
		if(SMPL_Link(&linkID) == SMPL_SUCCESS)						// if successful break from loop
		{
			connected = TRUE;										// set connected flag
			break;
		}
		
		wait(QUICK_CONNECT_TIME);									// wait quick time for reconnect
	}
	
	if(!connected)													// no connection slow reconnect attempts
	{
		do
		{
			wait(LONG_CONNECT_TIME);								// wait longer since CTC is offline
			BSP_TOGGLE_LED2();	// DEBUG
			SMPL_Send(SMPL_LINKID_USER_UUD, message, sizeof(message));
		}
		while(SMPL_Link(&linkID) != SMPL_SUCCESS);					// loop while not connected
	}
	
	SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXON, 0);			// turn radio on

	BSP_TURN_OFF_LED2();	// DEBUG
	
	message[TYPE]	   = RTS_IDENTIFY;								// send zone ID information
	message[ZONE_ID]   = zone;
	message[BATT_LIFE] = readBat();
	SMPL_Send(linkID, message, sizeof(message));
	
	while(gotMessage == FALSE)		//DEBUG
	{
		BSP_TURN_ON_LED1();
		BSP_TURN_ON_LED2();
	}
	BSP_TURN_OFF_LED1();
	BSP_TURN_OFF_LED2();
	
	if(gotMessage)
	{
		SMPL_Receive(linkID, message, &size);				// receive confirmation and set new sleep time
		sleepTime = message[SLEEP_TIME];
	
		gotMessage = FALSE;									// reset message flag
	}
	else		// DEBUG blink led's if no ack message
	{
		BSP_TURN_ON_LED1();
		BSP_TURN_ON_LED2();
		wait(1);
		BSP_TOGGLE_LED1();
		BSP_TOGGLE_LED2();
		wait(1);
		BSP_TOGGLE_LED1();
		BSP_TOGGLE_LED2();
		wait(1);
		BSP_TOGGLE_LED1();
		BSP_TOGGLE_LED2();
		wait(1);
		BSP_TOGGLE_LED1();
		BSP_TOGGLE_LED2();
		wait(1);
		BSP_TOGGLE_LED1();
		BSP_TOGGLE_LED2();	
	}
	
	SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXIDLE, 0);	// turn radio off		
}

uint8_t readTemp()
{
	float 	temp=0;
	int 	ADCvalue;
	int 	i;
	uint8_t ret;
	
	ADC12CTL1 &= ~ADC12CSTARTADD0;
	
	for(i = 0; i < 5; i++)						// read temperature by averaging 5 reads
	{
		ADC12CTL0 |= ADC12SC;					// Start conversion from ADC
		while(ADC12CTL1 & ADC12BUSY);			// Wait for the sample to complete (TODO: we should sleep here)
		ADCvalue = ADC12MEM0;
		
		#ifdef RTS_1							// empirically derived function
			temp += ADCvalue*0.3662 - 324.1; 
		#elif defined RTS_2
			temp += ADCvalue*0.3782 - 328.9;	
		#endif
	}
	temp /= 5;	
	
	ret = (uint8_t) temp;						
	__no_operation();
	 
	return (uint8_t)ret;
}

uint8_t readBat()
{
	int i;
	int ADCvalue;
	int voltage = 0;
	float test;
	
	ADC12CTL1 |= ADC12CSTARTADD0;
	
	for(i = 0; i < 5; i++)						// read battery voltage by averaging 5 reads
	{
		ADC12CTL0 |= ADC12SC;					// Start conversion from ADC
		while(ADC12CTL1 & ADC12BUSY);			// Wait for the sample to complete
		ADCvalue = ADC12MEM1;
		
		voltage += ADCvalue;
	}
	voltage /= 5;
	
	voltage = voltage >> 4;
	
	test = (2.0/256) * voltage;
	
	__no_operation();
	
	return voltage;	
}

void sendTemp()
{
	uint8_t size;
	int8_t 	sendAttempts=0;
  
  	message[TYPE]		 = RTS_REQUEST;					// REQ Message
	message[TEMPERATURE] = readTemp();					// Read temperature
	message[2]			 = readBat();					// TODO put batt life into message	 
 	 
 	sendAttempts = 0;
	gotMessage   = 0;
	while(gotMessage == 0)
	{	 	
		if(sendAttempts >= 5)							// only make 5 attempts or CTC error assumed
	 		RESET;										// CTC error force software reset
	
	 	sendAttempts++;									// count attempts
	 	
	 	SMPL_Send(linkID, message, sizeof(message));	// send message to CTC
	 	wait(2);										// wait 2 seconds before reatempt
	 	BSP_TOGGLE_LED2();	//DEBUG
	}
	
	SMPL_Receive(linkID, message, &size);				// receive confirmation and set new sleep time
	sleepTime = message[SLEEP_TIME];
	
	gotMessage = FALSE;									// reset message flag
		
	BSP_TURN_OFF_LED2();	//DEBUG
}

void wait(int seconds)
{
	numSeconds = 0;				
	
	while(numSeconds < seconds)		// wait specified number of seconds
		SLEEP;
}


#pragma vector = TIMER1_A0_VECTOR
__interrupt void Timer1_A0(void)
{
	TA1CCR0 += SLEEP_PERIOD;		// set new interrupt to occur in 1 second
	
	numSeconds++;					// incrment timer for wait() function
	LPM0_EXIT;						// exit low power mode for wait function to make decision
}

static uint8_t RxCallBack(linkID_t lid)
{
	if(lid == linkID)
		gotMessage = TRUE;				// set global flag
	return 0;
}
